package com.lenovo.tool;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;


public class TranslationInheritor {
    // Compare target and src XML files, and then find out those elements
    // with different translations in src XML file and output them to diff XML
    // file
    private static void saveInheritableStringsToFile(File target, File src,
            File outDir, String path) {
        try {
            Document targetDoc = DocumentUtils.openDocument(target);
            HashMap<String, Element> targetMap = XmlResUtil.parseXml(targetDoc);

            Document srcDoc = DocumentUtils.openDocument(src);
            HashMap<String, Element> srcMap = XmlResUtil.parseXml(srcDoc);

            HashMap<String, Element> extraSrcMap;
            File extraSrc = XmlResUtil.getAssociatedFile(src);
            if (extraSrc.exists()) {
                extraSrcMap = XmlResUtil.parseXml(DocumentUtils.openDocument(extraSrc));
            } else {
                extraSrcMap = new HashMap<String, Element>();
            }

            Document diffSrcDoc = DocumentUtils.createDocument();
            Node diffSrcRoot = diffSrcDoc.importNode(
                    srcDoc.getDocumentElement(), false);
            diffSrcDoc.appendChild(diffSrcRoot);

            Document diffTargetDoc = DocumentUtils.createDocument();
            Node diffTargetRoot = diffTargetDoc.importNode(
                    targetDoc.getDocumentElement(), false);
            diffTargetDoc.appendChild(diffTargetRoot);

            Iterator<String> itor = targetMap.keySet().iterator();
            while (itor.hasNext()) {
                String key = itor.next();
                String tv = targetMap.get(key).getTextContent();

                if (srcMap.containsKey(key)) {
                    String sv = srcMap.get(key).getTextContent();
                    if (tv != null && sv != null && !tv.equals(sv)) {
                        diffSrcRoot.appendChild(diffSrcDoc.importNode(
                                srcMap.get(key), true));
                        diffSrcRoot
                                .appendChild(diffSrcDoc.createTextNode("\n"));

                        diffTargetRoot.appendChild(diffTargetDoc.importNode(
                                targetMap.get(key), true));
                        diffTargetRoot.appendChild(diffTargetDoc
                                .createTextNode("\n"));
                    }
                } else if (extraSrcMap.containsKey(key)) {
                    String sv = extraSrcMap.get(key).getTextContent();
                    if (tv != null && sv != null && !tv.equals(sv)) {
                        diffSrcRoot.appendChild(diffSrcDoc.importNode(
                                extraSrcMap.get(key), true));
                        diffSrcRoot
                                .appendChild(diffSrcDoc.createTextNode("\n"));

                        diffTargetRoot.appendChild(diffTargetDoc.importNode(
                                targetMap.get(key), true));
                        diffTargetRoot.appendChild(diffTargetDoc
                                .createTextNode("\n"));
                    }
                }
            }

            AttributesHandler srcHandler = new AttributesHandler();

            SAXParserFactory fac = SAXParserFactory.newInstance();
            SAXParser parser = fac.newSAXParser();
            if (extraSrc.exists()) {
                parser.parse(extraSrc, srcHandler);
            }
            parser.parse(src, srcHandler);

            AttributesHandler targetHandler = new AttributesHandler();
            parser.parse(target, targetHandler);

            File diffSrcFile = new File(outDir, "src" + File.separator + path);
            if (diffSrcRoot.getChildNodes().getLength() > 0
                    && XmlResUtil.createNewFile(diffSrcFile)) {
                StreamResult result = new StreamResult(diffSrcFile);
                SAXTransformerFactory sff = (SAXTransformerFactory) SAXTransformerFactory
                        .newInstance();
                TransformerHandler th = sff.newTransformerHandler();

                Transformer tf = th.getTransformer();
                tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
                th.setResult(result);

                XmlResUtil.transformNode(DocumentUtils.isSameLine(diffSrcFile), th, diffSrcDoc,
                        srcHandler.getAttributeMap(), null);
            }

            File diffTargetFile = new File(outDir, "target" + File.separator
                    + path);
            if (diffTargetRoot.getChildNodes().getLength() > 0
                    && XmlResUtil.createNewFile(diffTargetFile)) {
                StreamResult result = new StreamResult(diffTargetFile);
                SAXTransformerFactory sff = (SAXTransformerFactory) SAXTransformerFactory
                        .newInstance();
                TransformerHandler th = sff.newTransformerHandler();

                Transformer tf = th.getTransformer();
                tf.setOutputProperty(OutputKeys.ENCODING, "utf-8");
                th.setResult(result);

                XmlResUtil.transformNode(DocumentUtils.isSameLine(diffTargetFile), th, diffTargetDoc,
                        targetHandler.getAttributeMap(), null);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        }

    }

    public static void findInheritableTranslations(File targetDir, File srcDir,
            File outDir, ArrayList<String> localeList,
            ArrayList<String> excludePathList) throws IOException {
        XmlResFileFilter filter = new XmlResFileFilter(true);

        for (String path : excludePathList) {
            filter.addExludePath(path);
        }

        int srcPathLen = srcDir.getAbsolutePath().length();
        ArrayList<File> srcFiles = filter.getLocaleXmlResFiles(srcDir,
                localeList);

        for (File srcFile : srcFiles) {
            String path = srcFile.getAbsolutePath().substring(srcPathLen + 1);

            File targetFile = new File(targetDir, path);
            if (targetFile.exists()) {
                saveInheritableStringsToFile(targetFile, srcFile, outDir, path);
            }
        }
    }

    public static void main(String[] args) {
        if (args.length != 1) {
            System.out.println("please enter the config file name");
            return;
        }

        File configFile = new File(args[0]);
        if (!configFile.exists() || !configFile.isFile()) {
            System.out.println("config file error");
            return;
        }

        try {
            PropConfigHandler handler = new PropConfigHandler();

            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser parser = factory.newSAXParser();
            parser.parse(configFile, handler);

            Properties props = handler.getProps();
            ArrayList<String> excludePathList = handler.getExcludePaths();

            File targetDir = new File(props.getProperty("targetdir"));
            File srcDir = new File(props.getProperty("srcdir"));
            File outDir = new File(props.getProperty("outdir"));
            String locales = props.getProperty("locales");
            ArrayList<String> localeList = new ArrayList<String>();
            if (locales != null) {
                StringTokenizer tokenizer = new StringTokenizer(locales, ",");
                while (tokenizer.hasMoreTokens()) {
                    localeList.add(tokenizer.nextToken());
                }
            }

            findInheritableTranslations(targetDir, srcDir, outDir, localeList,
                    excludePathList);
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
